////////////////////////////////////////////////////////////////////////////////
//
//  The MIT License
//
//  Copyright (c) 2008 - 2009. Dimarik
//
//  Permission is hereby granted, free of charge, to any person obtaining a copy
//  of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//  copies of the Software, and to permit persons to whom the Software is
//  furnished to do so, subject to the following conditions:
//
//  The above copyright notice and this permission notice shall be included in
//  all copies or substantial portions of the Software.
//
//  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//  THE SOFTWARE.
//
////////////////////////////////////////////////////////////////////////////////

package ru.goodcore.utils {

import flash.utils.describeType;
import flash.utils.getDefinitionByName;
import flash.utils.getQualifiedClassName;

/**
 *  DescribeTypeCache is a convenience class that is used to
 *  cache the return values of <code>flash.utils.describeType()</code>
 *  so that calls made subsequent times return faster.
 *
 *  This class also lets you set handler functions for specific value types.
 *  These will get called when the user tries to access these values on
 *  the <code>DescribeTypeCacheRecord</code> class.
 *
 *  @see mx.utils.DescribeTypeCacheRecord
 */
public class DescribeTypeCache
{

	//--------------------------------------------------------------------------
	//
	//  Class initialization
	//
	//--------------------------------------------------------------------------



	//--------------------------------------------------------------------------
	//
	//  Class variables
	//
	//--------------------------------------------------------------------------

	/**
	 *  @private
	 */
	private static var typeCache:Object = {};

	/**
	 *  @private
	 */
	private static var cacheHandlers:Object = {};

	//--------------------------------------------------------------------------
	//
	//  Class methods
	//
	//--------------------------------------------------------------------------

	/**
	 *  Calls <code>flash.utils.describeType()</code> for the first time and caches
         *  the return value so that subsequent calls return faster.
         *
         *  @param o Can be either a string describing a fully qualified class name or any
         *  ActionScript value, including all available ActionScript types, object instances,
         *  primitive types (such as <code>uint</code>), and class objects.
         *
         *  @return Returns the cached record.
         *
         *  @see flash.utils#describeType()
	 */
	public static function describeType(o:*):DescribeTypeCacheRecord
	{
		var className:String;

		if (o is String)
			className = o;
		else
			className = getQualifiedClassName(o);

		if (className in typeCache)
		{
			return typeCache[className];
		}
		else
		{
			if (o is String)
				o = getDefinitionByName(o);

			var typeDescription:XML = flash.utils.describeType(o);
			var record:DescribeTypeCacheRecord = new DescribeTypeCacheRecord();
			record.typeDescription = typeDescription;
			record.typeName = className;
			typeCache[className] = record;

			return record;
		}
	}

	/**
	 *  registerCacheHandler lets you add function handler for specific strings.
         *  These functions get called when the user refers to these values on a
         *  instance of <code>DescribeTypeCacheRecord</code>.
	 *
	 *  @param valueName String that specifies the value for which the handler must be set.
         *  @param handler Function that should be called when user references valueName.
	 */
	public static function registerCacheHandler(valueName:String, handler:Function):void
	{
		cacheHandlers[valueName] = handler;
	}

	/**
	 *  @private
	 */
	internal static function extractValue(valueName:String, record:DescribeTypeCacheRecord):*
	{
		if (valueName in cacheHandlers)
			return cacheHandlers[valueName](record);

		return undefined;
	}
	
}

}
